// Copyright 2022 Tencent
// Created by yousongyang on 2021/08/07.
//
#pragma once
#include <memory.h>
#include <cstddef>
#include <functional>
#include <iostream>
#include <stdexcept>
#include <type_traits>

// function_body 存储在栈上的function
// 初始化时不需要动态分配内存
// 仅适用于捕获列表均为POD类型的lambda
// 以及函数指针
// Buffer_size 为存储lambda闭包的最大大小
// 调用与原始函数指针持平 为std::function调用花费的50%
// 支持小buffer_size fast_function 转换为 大buffer_size fast_function

// O2

// 8bit
// 调用性能
// pod 92156  ||||| std::function 195476
// 拷贝自己
// pod 91410  ||||| std::function 348403
// 从lambda构造
// pod 79278  ||||| std::function 303265

// 32bit
// 调用性能
// pod 93758  ||||| std::function 187207
// 拷贝自己
// pod 82234  ||||| std::function 665941
// 从lambda构造
// pod 76206  ||||| std::function 616916

#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 501 && __cplusplus >= 201103L
#define CHECK_FAST_FUNCTION(TYPE)                                       \
    static_assert(std::is_trivially_copy_constructible<TYPE>::value,    \
                  "function_body is not trivially_copy_constructible"); \
    static_assert(!std::is_base_of<std::_Function_base, TYPE>::value, "not allow std::function 2 Function");
#else
#define CHECK_FAST_FUNCTION(TYPE)                                                                \
    static_assert(std::is_standard_layout<TYPE>::value, "function_body is not standard_layout"); \
    static_assert(!std::is_base_of<std::_Function_base, TYPE>::value, "not allow std::function 2 Function");
#endif

struct fast_function
{
};

template <typename Fun_Body, long unsigned int Buffer_size = 32>
class Function;

template <typename Big, typename Small>
struct allow;
template <typename Ret, typename... Args, long unsigned int Big_size, long unsigned Small_size>
struct allow<Function<Ret(Args...), Big_size>, Function<Ret(Args...), Small_size>>
{
    static const bool value = Big_size >= Small_size;
    static_assert(value, "Big fast_function 2 Small fast_function wrong");
};

template <typename Ret, typename... Args, long unsigned int Buffer_size>
class Function<Ret(Args...), Buffer_size> : fast_function
{
    using Func = Ret (*)(Args...);
    using Call = Ret (*)(const void *, Func, Args...);
    using self = Function<Ret(Args...), Buffer_size>;

public:
    Function() : func_body_(nullptr), call_ptr_(nullptr) {}
    Function(std::nullptr_t) : func_body_(nullptr), call_ptr_(nullptr) {}
    self &operator=(std::nullptr_t)
    {
        func_body_ = nullptr;
        call_ptr_ = nullptr;
        return *this;
    }
    operator bool() { return call_ptr_; }

    // for funciton_ptr
    Function(Ret (*func_ptr)(Args...)) : Function()
    {
        func_body_ = func_ptr;
        call_ptr_ = [](void *, Func f_ptr, Args... args) -> Ret
        { return f_ptr(std::forward<Args>(args)...); };
    }
    self &operator=(Ret (*func_ptr)(Args...))
    {
        func_body_ = func_ptr;
        call_ptr_ = [](void *, Func f_ptr, Args... args) -> Ret
        { return f_ptr(std::forward<Args>(args)...); };
        return *this;
    }
    // end

    // For self
    template <typename Func_body,
              typename std::enable_if<std::is_base_of<class fast_function, typename std::decay<Func_body>::type>::value &&
                                          allow<self, typename std::decay<Func_body>::type>::value,
                                      bool>::type = false>
    Function(Func_body &&fun) : Function()
    {
        Copy_from_same(std::forward<Func_body>(fun));
    }
    template <typename Func_body,
              typename std::enable_if<std::is_base_of<class fast_function, typename std::decay<Func_body>::type>::value &&
                                          allow<self, typename std::decay<Func_body>::type>::value,
                                      bool>::type = false>
    self &operator=(Func_body &&fun)
    {
        if (reinterpret_cast<void *>(this) == reinterpret_cast<void *>(&fun))
        {
            return *this;
        };
        Copy_from_same(std::forward<Func_body>(fun));
        return *this;
    }
    // end

    // For lambda
    template <typename Func_body,
              typename std::enable_if<!std::is_base_of<class fast_function, typename std::decay<Func_body>::type>::value,
                                      bool>::type = false>
    Function(Func_body &&fun) : Function()
    {
        using Type = typename std::decay<Func_body>::type;
        CHECK_FAST_FUNCTION(Type)
        static_assert(sizeof(Type) <= Buffer_size, "function_body too big");
        call_ptr_ = [](const void *object_ptr, Func, Args... args) -> Ret
        {
            return static_cast<Type *>(const_cast<void *>(object_ptr))->operator()(std::forward<Args>(args)...);
        };
        new (&buffer_) Type(*(static_cast<Type *>(&fun)));
    }
    template <typename Func_body,
              typename std::enable_if<!std::is_base_of<class fast_function, typename std::decay<Func_body>::type>::value,
                                      bool>::type = false>
    self &operator=(Func_body &&fun)
    {
        using Type = typename std::decay<Func_body>::type;
        CHECK_FAST_FUNCTION(Type)
        static_assert(sizeof(Type) <= Buffer_size, "function_body too big");
        call_ptr_ = [](const void *object_ptr, Func, Args... args) -> Ret
        {
            return static_cast<Type *>(const_cast<void *>(object_ptr))->operator()(std::forward<Args>(args)...);
        };
        new (&buffer_) Type(*(static_cast<Type *>(&fun)));
        return *this;
    }
    // end

    Ret operator()(Args... args) const
    {
        if (!call_ptr_)
            throw std::runtime_error("bad function");
        // 如果没有加fno-exceptions 则开启
        return call_ptr_(&buffer_, func_body_, std::forward<Args>(args)...);
    }
    ~Function() {}

private:
    template <typename Func_body>
    void Copy_from_same(Func_body &&fun)
    {
        call_ptr_ = fun.call_ptr_;
        memcpy(&buffer_, &fun, sizeof(Func_body) - sizeof(Call));
    }

public:
    union
    {
        typename std::aligned_storage<Buffer_size, sizeof(size_t)>::type buffer_;
        Func func_body_;
    };
    Call call_ptr_;
};